{% extends "base.html" %}

{% block main %}

<div id="app" class="container-lg m-4">
    <div class="row mt-2">
        <div class="col-md-12 mt-2">
            <div class="card">
                <div class="card-header" >
                    <span class="badge badge-success" v-if="model == 1">Online Model</span>
                    <span class="badge badge-warning" v-if="model == 2">Snapshot Model</span>
                    <div>
                        <i class="fa fa-server fa-2x"></i> 
                        <label class="h-title">{% raw %}{{ds.ds.ServerName}}{% endraw %} </label>    
                    </div>

                </div>
                <div class="card-body">
                    <div class="row">
                        <div class="col-md-9">
                            <div id="requestChart" class="col-md-12" style="height:320px; "></div>
                        </div>
                        
                        <div class="col-md-3">
                            Start time: {% raw %}{{ds.ds.baseStatsTable.Start_time}}{% endraw %} </br>
                            Version: {% raw %}{{ds.ds.baseStatsTable.Version}}{% endraw %} </br>
                            Num. Regions: {% raw %}{{ds.ds.baseStatsTable.Num_Regions}}{% endraw %} </br>
                            Last contact: {% raw %}{{ds.ds.baseStatsTable.Last_contact}}{% endraw %} </br>
                            Last update: {% raw %}{{ds.ts}}{% endraw %}</br>
                            <hr>
                            Request Per Second: {% raw %}{{ds.ds.requestStatsTable.Request_Per_Second | formatNum}}{% endraw %}</br>
                            Max Request Per Second: {% raw %}{{request.Max_Request_Per_Second[1] | formatNum}}{% endraw %} <br>
                        </div>

                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="mt-2 col-md-6">
            <div class="card">
                <div class="card-header bd-callout-info">
                   <div>
                    <i class="fa fa-files-o fa-2x"></i>
                    <label class="b-title">Request</label>
                   </div> 
                    <div class="row">
                        <div class="col-md-4">
                            Read Request Count: {% raw %}{{ds.ds.requestStatsTable.Read_Request_Count | formatNum}}{% endraw%}</br>
                        </div>
                        <div class="col-md-4">
                            Filtered Read Request Count: {% raw %}{{ds.ds.requestStatsTable.Filtered_Read_Request_Count}}{%endraw%}</br>
                        </div>
                        <div class="col-md-4">
                            Write Request Count: {% raw %}{{ds.ds.requestStatsTable.Write_Request_Count}}{% endraw %}</br>
                        </div>
                    </div>
                </div>
                <div class="card-body">
                    <div class="row">
                        <div id="requestStatsChart" class="col-md-12" style="height:320px; "></div>
                    </div>
                </div>
            </div>
        </div>

        <div class="mt-2 col-md-6">
            <div class="card">
                <div class="card-header">
                    <div>
                        <i class="fa fa-pie-chart fa-2x"></i>
                        <label class="b-title">Memory</label>
                    </div>

                    <div class="row">
                        <div class="col-md-4">
                            Max Heap: {% raw %}{{ds.ds.memoryStatsTable.Max_Heap | formatStorageUnit}}{% endraw %}</br>
                        </div>
                        <div class="col-md-4">
                            Used Heap: {% raw %}{{ds.ds.memoryStatsTable.Used_Heap | formatStorageUnit}}{% endraw %}</br>
                        </div>
                        <div class="col-md-4">
                            Memstore Size: {% raw %}{{ds.ds.memoryStatsTable.Memstore_Size | formatStorageUnit}}{% endraw %}</br>
                        </div>
                    </div>
                </div>
    
                <div class="card-body">
                    <div class="row">
                        <div id="heapChart" class="col-md-4" style="height:320px; "></div>
                        <div id="memstoreChart" class="col-md-8" style="height:320px; "></div>
                    </div>
                </div>
            </div>
        </div>


        
    <div class="mt-2 col-md-6">
        <div class="card">
            <div class="card-header">
                <div>
                    <i class="fa fa-folder-open-o fa-2x"></i>
                    <label class="b-title">Store</label>
                </div>

                <div class="row">
                    <div class="col-md-4">
                        Num. Stores: {% raw %}{{ds.ds.storeStatsTable.Num_Stores | formatNum}}{% endraw %}</br>
                        Num. Storefiles: {% raw %}{{ds.ds.storeStatsTable.Num_Storefiles | formatNum}}{% endraw %}</br>
                    </div>

                    <div class="col-md-4">
                        Storefile Size: {% raw %}{{ds.ds.storeStatsTable.Storefile_Size | formatStorageUnit}}{% endraw%}</br>
                        Storefile Size Uncompressed: {% raw %}{{ds.ds.storeStatsTable.Storefile_Size_Uncompressed | formatStorageUnit}}{% endraw %}</br>
                    </div>

                    <div class="col-md-4">
            Index Size: {% raw %}{{ds.ds.storeStatsTable.Index_Size | formatStorageUnit}}{% endraw %}</br>
            Bloom Size: {% raw %}{{ds.ds.storeStatsTable.Bloom_Size | formatStorageUnit}}{% endraw %}</br>
                    </div>
                </div>
            </div>

            <div class="card-body">
                <div class="row">
                    <div id="storefilesChart" class="col-md-4" style="height:320px; "></div>
                    <div id="storeSizeChart" class="col-md-8" style="height:320px; "></div>
                </div>
            </div>
        </div>
    </div>

    <div class="mt-2 col-md-6">
        <div class="card">
            <div class="card-header">
                <div>
                    <i class="fa fa-gears fa-2x"></i>
                    <label class="b-title">Compaction</label>
                </div>
                <div class="row">

                    <div class="col-md-6">
                        Num. Compacting Cells: {% raw %}{{ds.ds.compactionStatsTable.Num_Compacting_Cells | formatNum}}{% endraw %} <br>
                        Num. Compacted Cells : {% raw %}{{ds.ds.compactionStatsTable.Num_Compacted_Cells | formatNum}}{% endraw %}
                    </div>

                    <div class="col-md-6">
                        Remaining Cells: {% raw %}{{ds.ds.compactionStatsTable.Remaining_Cells | formatNum}}{% endraw %} <br>
                        Compaction Progress: {% raw %}{{ds.ds.compactionStatsTable.Compaction_Progress }}{% endraw %} %
                    </div>
                </div>
            </div>

            <div class="card-body">
                <div id="cellsChart"  style="height:320px;"></div>
            </div>
        </div>
    </div>
    </div>





</div>
{% endblock %}

{% block vue %}
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                model: 0,  //1：实时模式，2：快照模式
                job: null, //用于快照模式清除轮询任务
                sId: 0,

                id: 0,
                idRange: [-1, -1],
                //redraw: true,

                ds: {
                    ts: '',
                    ds: {
                        "ServerName": "",
                        "baseStatsTable": { "Start_time": "", "Last_contact": "", "Version": "", "Requests_Per_Second": 0, "Num_Regions": 0 },
                        "memoryStatsTable": { "Used_Heap": 0, "Max_Heap": 0, "Memstore_Size": 0 }, "requestStatsTable": { "Request_Per_Second": 0, "Read_Request_Count": 0, "Filtered_Read_Request_Count": 0, "Write_Request_Count": 0 },
                        "storeStatsTable": { "Num_Stores": 0, "Num_Storefiles": 0, "Storefile_Size_Uncompressed": 0, "Storefile_Size": 0, "Index_Size": 0, "Bloom_Size": 0 },
                        "compactionStatsTable": { "Num_Compacting_Cells": 0, "Num_Compacted_Cells": 0, "Remaining_Cells": 0, "Compaction_Progress": 0 }
                    }
                },

                xNum: 1, //当xNum > 100时，shift = true
                maxNum: 100,
                shift: false,

                request: { chart: null, Max_Request_Per_Second: ['', 0], },
                requestStats: { chart: null, },
                heap: { chart: null, },
                memstore: { chart: null, },
                storefiles: { chart: null },
                storeSize: { chart: null },
                cells:{chart: null,},
            }
        },
        mounted() {
            this.init();
        },
        methods: {
            init() {
                let sId = this.getQueryString('sId');
                let st = this.getQueryString('st');
                let et = this.getQueryString('et');
                st = new Date(st).getTime() / 1000;
                et = new Date(et).getTime() / 1000;

                if (sId == null || isNaN(sId)) this.sId = 0;
                else this.sId = sId;

                if (st == null || et == null || isNaN(st) || isNaN(et) || st >= et) {
                    this.startM1();
                } else {  //尝试进入M2
                    axios.get("/api/getIdRange", { params: { 'st': st, 'et': et } }).then(
                        (res) => {
                            let idRange = res.data.data.idRange;
                            if (idRange[0] != -1 && idRange[1] != -1) { //如果idRange合法
                                this.idRange = idRange;
                                this.startM2(); //启动M2
                            } else {
                                this.startM1(); //转到M1
                            }
                        })
                        .catch(function (error) { console.log(error); });
                }

            },
            startM1() {
                this.model = 1;
                console.log("Real Time Model...")
                this.getFirstData();
                this.job = setInterval(this.getNextData, 3000);
            },
            startM2() {
                this.model = 2;
                console.log("Snapshoot Model...")
                this.id = this.idRange[0];
                //this.redraw = false; //不马上更新
                this.maxNum = 200; //扩大maxNum;
                this.getFirstData();
                this.job = setInterval(this.getNextData, 100);
            },
            getFirstData() {
                axios.get("/api/getServerNextData", { params: { 'id': this.id, 'sId': this.sId } }).then(
                    (res) => {
                        let ds = res.data.data.ds;
                        this.id = ds.id;
                        this.ds = ds;
                        console.log(this.ds)
                        this.initCharts();
                    })
                    .catch(function (error) { console.log(error); });
            },
            getNextData() {
                if (this.model == 2 && this.id > this.idRange[1]) {
                    //最后一次刷新表格
                    this.drawAll();
                    clearInterval(this.job);
                    return;
                }
                axios.get("/api/getServerNextData", { params: { 'id': this.id, 'sId': this.sId } }).then(
                    (res) => {
                        let ds = res.data.data.ds;
                        if (!(ds.id > this.id)) { return; } //如果不是新数据，则跳过

                        this.id = ds.id;
                        this.ds = ds;

                        this.updateCharts();
                        if (++this.xNum >= this.maxNum) this.shift = true;
                    })
                    .catch(function (error) { console.log(error); });
            },
            initCharts() {
                Highcharts.setOptions({ global: { useUTC: false } });
                this.request.chart = new Highcharts.Chart('requestChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    legend:{enabled:false},
                    plotOptions: { series: { allowPointSelect: true } },
                    // chart: { type: 'areaspline', },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Requests Per Second' },
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'RPS', color: '#4285f6', data: [] }]
                });

                this.requestStats.chart = new Highcharts.Chart('requestStatsChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Requests Count' },
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'Read_Request_Count', color: '#34a855', data: [] }, { name: 'Write_Request_Count', color: '#3d88f1', data: [] }, { name: 'Filtered_Read_Request_Count', color: '#fabc05', data: [] }]
                });

                this.heap.chart = new Highcharts.Chart('heapChart', {
                    credits: { enabled: false },
                    exporting: { enabled: false },
                    boost: { useGPUTranslations: true },
                    chart: {
                        plotBackgroundColor: null, plotBorderWidth: null, plotShadow: false,
                        type: 'pie',
                    },
                    title: { text: 'Heap' },
                    tooltip: { pointFormat: '{series.name}: <b>{point.percentage:.2f}%</b>' },
                    plotOptions: {
                        pie: {
                            allowPointSelect: true, cursor: 'pointer',
                            dataLabels: { enabled: false }, showInLegend: false,
                        }
                    },
                    series: [{
                        name: 'Size', colorByPoint: true,
                        data: [{ color: '#336699', name: 'Free Heap', y: 0, }, { color: '#cccc00', name: 'Used Heap', y: 0 }]
                    }]
                });

                this.memstore.chart = new Highcharts.Chart('memstoreChart', {
                    credits: { enabled: false },
                    plotOptions: { series: { allowPointSelect: true } },
                    chart: { zoomType: 'x',type: 'areaspline', },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Memstore Size' },
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'Memstore', color: '#058DC7', data: [] }]
                });

                this.storefiles.chart = new Highcharts.Chart('storefilesChart', {
                    credits: { enabled: false },
                    plotOptions: { series: { allowPointSelect: true } },
                    chart: { zoomType: 'x',type: 'areaspline', },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Num. Storefiles' },
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'Storefiles', color: '#058DC7', data: [] }]
                });

                this.storeSize.chart = new Highcharts.Chart('storeSizeChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Requests Count' },
                    yAxis: { title: { text: '' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'Storefile_Size_Uncompressed', color: '#b46927', data: [] }, { name: 'Storefile_Size', color: '#058DC7', data: [] }, { name: 'Index_Size', color: '#50B432', data: [] }, { name: 'Bloom_Size', color: '#862586', data: [] }]
                });

                this.cells.chart = new Highcharts.Chart('cellsChart', {
                    credits: { enabled: false },
                    chart: { zoomType: 'x' },
                    plotOptions: { series: { allowPointSelect: true } },
                    boost: { useGPUTranslations: true },
                    title: { text: 'Compaction Status' },
                    yAxis: { title: { text: 'Num.' }, floor: 0, },
                    xAxis: { type: 'datetime', },
                    series: [{ name: 'Compacting Cells', color: '#3c5492', data: [] }, { name: 'Compacted Cells', color: '#009001', data: [] }, { name: 'Remaining Cells', color: '#fabc05', data: []}]
                });

                this.updateCharts();
            },
            updateCharts() {
                let ts = (new Date(this.ds.timestamp)).getTime()
                let ds = this.ds.ds;
                //let redraw = this.redraw;
                let redraw = false;
                let shift = this.shift;

                //set max_request_per_second
                if (ds.requestStatsTable.Request_Per_Second >= this.request.Max_Request_Per_Second[1]) {
                    this.request.Max_Request_Per_Second = [ts, ds.requestStatsTable.Request_Per_Second];
                }

                this.request.chart.series[0].addPoint([ts, ds.requestStatsTable.Request_Per_Second], redraw, shift, true);
                this.requestStats.chart.series[0].addPoint([ts, ds.requestStatsTable.Read_Request_Count], redraw, shift, true);
                this.requestStats.chart.series[1].addPoint([ts, ds.requestStatsTable.Write_Request_Count], redraw, shift, true);
                this.requestStats.chart.series[2].addPoint([ts, ds.requestStatsTable.Filtered_Read_Request_Count], redraw, shift, true);
                this.heap.chart.series[0].setData([ds.memoryStatsTable.Max_Heap - ds.memoryStatsTable.Used_Heap, ds.memoryStatsTable.Used_Heap]);

                this.memstore.chart.series[0].addPoint([ts, ds.memoryStatsTable.Memstore_Size], redraw, shift, true);

                this.storefiles.chart.series[0].addPoint([ts, ds.storeStatsTable.Num_Storefiles], redraw, shift, true);
                this.storeSize.chart.series[0].addPoint([ts, ds.storeStatsTable.Storefile_Size_Uncompressed], redraw, shift, true);
                this.storeSize.chart.series[1].addPoint([ts, ds.storeStatsTable.Storefile_Size], redraw, shift, true);
                this.storeSize.chart.series[2].addPoint([ts, ds.storeStatsTable.Index_Size], redraw, shift, true);
                this.storeSize.chart.series[3].addPoint([ts, ds.storeStatsTable.Bloom_Size], redraw, shift, true);

                this.cells.chart.series[0].addPoint([ts, ds.compactionStatsTable.Num_Compacting_Cells], redraw, shift, true);
                this.cells.chart.series[0].addPoint([ts, ds.compactionStatsTable.Num_Compacted_Cells], redraw, shift, true);
                this.cells.chart.series[1].addPoint([ts, ds.compactionStatsTable.Remaining_Cells], redraw, shift, true);


                if(this.model == 1){
                    this.drawAll()
                }
                else if (this.model == 2 && this.id % 10 == 0) {
                    this.drawAll()
                }

            },
            drawAll() {
                this.request.chart.redraw();
                this.requestStats.chart.redraw();
                this.memstore.chart.redraw();
                this.storefiles.chart.redraw();
                this.storeSize.chart.redraw();
                this.cells.chart.redraw();
            },

            getQueryString(name) {
                var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
                var reg_rewrite = new RegExp("(^|/)" + name + "/([^/]*)(/|$)", "i");
                var r = window.location.search.substr(1).match(reg);
                var q = window.location.pathname.substr(1).match(reg_rewrite);
                if (r != null) { return unescape(r[2]); }
                else if (q != null) { return unescape(q[2]); }
                else { return null; }
            },
            /*
            addClass(e) {
                if (e == "model") {
                    switch (this.model) {
                        case 1: return "label-success";
                        case 2: return "label-warning";
                        default: return "label-default";
                    }
                }
            },*/
        },
        filters: {
            formatStorageUnit(d) {
                if (d == undefined) { return '0 KB' }
                if (d >= 1073741824) return (d / 1073741824).toFixed(2) + " TB"
                if (d >= 1048576) return (d / 1048576).toFixed(2) + " GB"
                if (d >= 1024) return (d / 1024) + " MB"
                return d + " KB"
            },

            formatNum(n) {
                if (n == undefined) { return '0' }
                n = n + ""
                let re = /\d{1,3}(?=(\d{3})+$)/g;
                let n1 = n.replace(/^(\d+)((\.\d+)?)$/, function (s, s1, s2) { return s1.replace(re, "$&,") + s2; });
                return n1;
            },

            fix2(d) {
                if (d == undefined) { return '' }
                return Number(d).toFixed(2);
            }
        }
    })

</script>
{% endblock %}